1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.webmacro.resource;
24
25 import org.webmacro.Broker;
26 import org.webmacro.TemplateException;
27 import org.webmacro.WMConstants;
28 import org.webmacro.engine.WMTemplate;
29 import org.webmacro.servlet.LocaleTool;
30 import org.webmacro.util.NativeAsciiReader;
31
32 import java.io.*;
33 import java.net.URL;
34 import java.util.HashMap;
35 import java.util.Locale;
36 import java.util.Properties;
37
38 /***
39 * FileTemplate objects read their template data from a text file.
40 */
41
42 public class URLTemplate extends WMTemplate
43 {
44
45 /***
46 * CVS revision
47 */
48
49 public static final String RCS = "@(#) $Id: URLTemplate.java,v 1.11 2005/10/31 02:46:41 lanesharman Exp $";
50
51 /***
52 * The location of the resourse (file) this template was read from.
53 */
54
55 private final URL _url;
56
57 /***
58 * The physical file referred to by "file:" and "jar:" URLs
59 */
60
61 private File underLyingFile = null;
62
63 /***
64 * The time the underlying file was last modified
65 */
66
67 private long underLyingFileLastModTime = 0;
68
69 /***
70 * Cache for any per-directory encoding files
71 */
72
73 private final HashMap propertiesCache = new HashMap();
74
75 private String _inputEncoding = null;
76 private String _outputEncoding = null;
77 private Locale _outputLocale = null;
78
79 /***
80 * A dummy object used as a place holder in the encoding cache
81 */
82
83 private static final Object dummy = new Object();
84
85 /***
86 * Instantiate a template based on the specified file.
87 * We use can use the special case or URLs like
88 * <pre>
89 * file:xxxxxx
90 * or
91 * jar:xxxxxx!yyyyyy
92 *</pre>
93 * extracting the xxxxxx. In the latter case the reference is to the jar containing the
94 * template.
95 */
96
97 public URLTemplate (
98 Broker broker,
99 URL templateURL
100 )
101 {
102 super(broker);
103 _url = templateURL;
104 String _u = _url.toExternalForm();
105
106 _log.debug("URLTemplate: " + _u);
107
108 if (_u.startsWith("jar:"))
109 {
110 int p = _u.indexOf("!");
111 _u = _u.substring(4, p);
112 }
113
114 if (_u.startsWith("file:"))
115 {
116 underLyingFile = new File(_u.substring(5));
117 underLyingFileLastModTime = underLyingFile.lastModified();
118 }
119
120 setupLocalProperties();
121 }
122
123 /***
124 * URL based templates are difficult to detect as changed in general, but the two
125 * special cases can be determined for reloading.
126 * <pre>
127 * file:[path] and
128 * jar:file:[jarpath]![path]
129 * </pre>
130 * Imply a reference to the actual file.
131 */
132
133 public boolean shouldReload ()
134 {
135 if (underLyingFile == null) return false;
136 long lastMod = underLyingFile.lastModified();
137
138 return ((lastMod > 0) && (lastMod > underLyingFileLastModTime));
139 }
140
141
142 /***
143 * Look for TemplateEncoding in a file WebMacro.local in the same
144 * directory as the template
145 *
146 * TODO - should make the encoding cache a bit smarter- doesn't detect
147 * if the file changes
148 */
149
150 private void setupLocalProperties ()
151 {
152 InputStream is = null;
153 URL u = null;
154
155 try
156 {
157
158 u = new URL(_url, WMConstants.WEBMACRO_LOCAL_FILE);
159 _log.debug("Looking for encodings file: " + u);
160 Object obj = propertiesCache.get(u);
161
162 if (obj != null)
163 {
164 return;
165 }
166
167 Properties p = new Properties();
168 is = u.openStream();
169 p.load(is);
170 _inputEncoding = p.getProperty(WMConstants.TEMPLATE_INPUT_ENCODING);
171 _outputEncoding = p.getProperty(WMConstants.TEMPLATE_OUTPUT_ENCODING);
172
173 String loc = p.getProperty(WMConstants.TEMPLATE_LOCALE);
174 if (loc != null)
175 {
176 _outputLocale = LocaleTool.buildLocale(loc);
177 }
178
179 propertiesCache.put(u, dummy);
180
181
182 }
183 catch (Exception e)
184 {
185
186
187
188 propertiesCache.put(u, dummy);
189 }
190 finally
191 {
192 if (_inputEncoding == null)
193 {
194 _inputEncoding = getDefaultEncoding();
195 }
196
197 if (is != null)
198 {
199 try
200 {
201 is.close();
202 }
203 catch (Exception ignore)
204 {
205 }
206 }
207 }
208 }
209
210 /***
211 * Get the stream the template should be read from. Parse will
212 * call this method in order to locate a stream.
213 *
214 */
215 protected Reader getReader () throws IOException
216 {
217 _log.debug("Using encoding " + _inputEncoding);
218
219 if (_inputEncoding.equals("native_ascii"))
220 {
221 return new NativeAsciiReader(
222 new InputStreamReader(_url.openStream(), "ASCII"));
223 }
224 else
225 {
226 return new BufferedReader(
227 new InputStreamReader(_url.openStream(), _inputEncoding));
228 }
229 }
230
231 /***
232 * return the URL for the current template.
233 */
234 public URL getURL ()
235 {
236 return _url;
237 }
238
239 /***
240 * Return a name for this template. For example, if the template reads
241 * from a file you might want to mention which it is--will be used to
242 * produce error messages describing which template had a problem.
243 */
244 public String toString ()
245 {
246 return "URLTemplate:" + _url;
247 }
248
249 public void parse () throws IOException, TemplateException
250 {
251 super.parse();
252 if ((_outputEncoding != null)
253 && (getParam(WMConstants.TEMPLATE_OUTPUT_ENCODING) == null))
254 {
255 _log.debug("Setting output encoding to " + _outputEncoding);
256 setParam(WMConstants.TEMPLATE_OUTPUT_ENCODING, _outputEncoding);
257 }
258 if ((_outputLocale != null)
259 && (getParam(WMConstants.TEMPLATE_LOCALE) == null))
260 {
261 _log.debug("Setting output locale to " + _outputLocale);
262 setParam(WMConstants.TEMPLATE_LOCALE, _outputLocale);
263 }
264 }
265 }